package com.wonders.framework.auto.builder.code;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.wonders.framework.auto.builder.code.convert.BaseTagConvert;
import com.wonders.framework.auto.builder.code.convert.instance.DefaultConvert;
import com.wonders.framework.auto.builder.code.convert.instance.DaoQueryConvert;
import com.wonders.framework.auto.builder.code.convert.instance.EntityFunctionConvert;
import com.wonders.framework.auto.builder.code.convert.instance.EntityPropertyConvert;
import com.wonders.framework.auto.builder.code.convert.instance.EntityToStringConvert;
import com.wonders.framework.auto.builder.code.convert.instance.FormInputConvert;
import com.wonders.framework.auto.builder.code.convert.instance.HasDateConvert;
import com.wonders.framework.auto.builder.code.convert.instance.ListGridConvert;
import com.wonders.framework.auto.builder.code.convert.instance.ListQueryConvert;
import com.wonders.framework.auto.builder.code.entity.vo.BuildColumn;
import com.wonders.framework.auto.builder.code.entity.vo.BuildTable;
import com.wonders.framework.auto.builder.code.entity.vo.ColumnInfo;
import com.wonders.framework.auto.builder.code.service.TableService;
import com.wonders.framework.util.dao.FormatUtil;
import com.wonders.framework.util.web.ApplicationUtil;

/**
 * 代码生成器
 * 
 * @author WuBin
 * 
 */
public class CodeBuilder {

	/**
	 * 定义的标签
	 */
	private final static String[] tags = { "#packageName#", "#className#",
			"#instanceName#", "#primaryClass#", "#primaryFunction#",
			"#primaryName#", "#abbrName#", "#tableName#", "#dao-hasDate#",
			"#dao-query#", "#entity-hasDate#", "#bo-property#",
			"#entity-function#", "#vo-toString#", "#bo-toString#",
			"#vo-property#", "#list-query#", "#list-grid#", "#list-query#",
			"#form-input#" };

	/**
	 * 生成的文件类型
	 */
	private final static String[] files = { "Bo.java", "Vo.java",
			"Controller.java", "Service.java", "ServiceImpl.java", "Dao.java",
			"DaoImpl.java", "List.jsp", "Form.jsp" };

	/**
	 * 生成代码
	 * 
	 * @param ignorePrefix
	 *            是否忽略前缀
	 * @param packageName
	 *            包名
	 * @param tableNames
	 *            表名
	 */
	public void build(boolean ignorePrefix, String packageName,
			String... tableNames) {
		ClassPathXmlApplicationContext classPathXmlApplicationContext = null;
		try {
			// 获取实例
			classPathXmlApplicationContext = new ClassPathXmlApplicationContext(
					"classpath*:springMVC-servlet.xml");
			TableService tableService = ApplicationUtil
					.getBean(TableService.class);
			System.out.println("--------自动生成代码开始啦--------");
			for (String tableName : tableNames) {
				if (StringUtils.isEmpty(tableName)) {
					System.out.println("忽略表名空值");
					continue;
				}
				// 查询表结构
				List<ColumnInfo> columnList = tableService.getColumn(tableName);
				if (columnList.size() < 1) {
					System.out.println("表" + tableName + "不存在");
					continue;
				}
				try {
					// 分析表结构
					BuildTable buildTable = analyze(ignorePrefix, tableName,
							columnList);
					System.out.println("分析表" + tableName + "完成");
					if (!buildTable.isHasPrimary()) {
						System.out.println("暂不支持无主键的表生成代码，忽略表" + tableName);
						continue;
					}
					buildTable.setPackageName(packageName);
					// 生成文件
					for (String file : files) {
						createFile(buildTable, file);
						System.out.println("生成表" + tableName + "文件" + file
								+ "完成");
					}
				} catch (Exception e) {
					System.out.println("生成表" + tableName + "代码出现问题");
					e.printStackTrace();
				}
			}
			System.out.println("--------自动生成代码结束啦--------");
		} finally {
			if (classPathXmlApplicationContext != null) {
				classPathXmlApplicationContext.close();
			}
		}
	}

	/**
	 * 分析表结构
	 * 
	 * @param ignorePrefix
	 *            是否忽略前缀
	 * @param tableName
	 *            表名
	 * @param columnList
	 *            数据项
	 * @return 创建实例
	 */
	private BuildTable analyze(Boolean ignorePrefix, String tableName,
			List<ColumnInfo> columnList) {
		BuildTable buildTable = new BuildTable();
		buildTable.setTableName(tableName.toUpperCase());
		if (ignorePrefix) {
			buildTable.setInstanceName(FormatUtil.parseField(tableName
					.substring(tableName.indexOf("_") + 1).toLowerCase()));
		} else {
			buildTable.setInstanceName(FormatUtil.parseField(tableName
					.toLowerCase()));
		}
		buildTable.setClassName(buildTable.getInstanceName().substring(0, 1)
				.toUpperCase()
				+ buildTable.getInstanceName().substring(1));
		buildTable.setAbbrName(buildTable.getInstanceName().substring(0, 1));
		for (ColumnInfo columnInfo : columnList) {
			BuildColumn buildColumn = new BuildColumn();
			buildColumn.setPropertyName(FormatUtil.parseField(columnInfo
					.getColumnName().toLowerCase()));
			buildColumn.setFunctionName(buildColumn.getPropertyName()
					.substring(0, 1).toUpperCase()
					+ buildColumn.getPropertyName().substring(1));
			buildColumn
					.setPrimary("P".equals(columnInfo.getConstraintType()) ? true
							: false);
			buildColumn.setRequired("N".equals(columnInfo.getNullable()) ? true
					: false);
			buildColumn.setPropertyMean(StringUtils.isNotBlank(columnInfo
					.getComments()) ? columnInfo.getComments() : buildColumn
					.getPropertyName());
			// 分析数据类型
			if ("NUMBER".equals(columnInfo.getDataType())) {
				if (columnInfo.getDataScale() > 0) {

				} else {
					if (columnInfo.getDataPrecision() > 9) {
						buildColumn.setTypeName("Long");
					} else {
						buildColumn.setTypeName("Integer");
					}
					buildColumn.setMaxLength(String.valueOf(columnInfo
							.getDataPrecision()));
				}
			} else if ("VARCHAR2".equals(columnInfo.getDataType())) {
				buildColumn.setTypeName("String");
				buildColumn.setMaxLength(String.valueOf(columnInfo
						.getDataLength()));
			} else if ("DATE".equals(columnInfo.getDataType())) {
				buildTable.setHasDate(true);
				buildColumn.setTypeName("Date");
			} else {
				System.out.println("暂不支持" + columnInfo.getDataType()
						+ "数据类型，忽略表" + tableName + "列"
						+ columnInfo.getColumnName());
				continue;
			}
			if (buildColumn.isPrimary()) {
				buildTable.setHasPrimary(true);
				buildTable.setPrimaryClass(buildColumn.getTypeName());
				buildTable.setPrimaryFunction(buildColumn.getFunctionName());
				buildTable.setPrimaryName(buildColumn.getPropertyName());
			}
			buildTable.getColumns().add(buildColumn);
		}
		return buildTable;
	}

	/**
	 * 生成文件
	 * 
	 * @param buildTable
	 *            创建实例
	 * @param fileType
	 *            文件类型
	 * @throws IOException
	 */
	private void createFile(BuildTable buildTable, String fileType)
			throws IOException {
		String type = fileType.substring(fileType.lastIndexOf(".") + 1);
		// 分析文件后缀
		String fileName = "";
		String templateName = "";
		if ("java".equals(type)) {
			if ("Bo.java".equals(fileType)) {
				fileName = buildTable.getClassName() + "." + type;
			} else {
				fileName = buildTable.getClassName() + fileType;
			}
			templateName = fileType.substring(0, fileType.lastIndexOf("."));
		} else if ("jsp".equals(type)) {
			fileName = buildTable.getInstanceName() + fileType;
			templateName = fileType.substring(0, fileType.lastIndexOf("."));
		} else {
			return;
		}
		BufferedReader bufferedReader = null;
		FileOutputStream out = null;
		try {
			// 读取模板
			InputStream inputStream = ClassLoader
					.getSystemResourceAsStream("com/wonders/framework/auto/builder/code/template/"
							+ templateName);
			bufferedReader = new BufferedReader(new InputStreamReader(
					inputStream));
			out = new FileOutputStream(new File("C://Users/WuBin/Desktop/"
					+ fileName));
			for (String temp = null; (temp = bufferedReader.readLine()) != null; temp = null) {
				// 替换标签并写入文件
				out.write(replaceTags(temp, buildTable).getBytes());
			}
		} finally {
			if (bufferedReader != null) {
				bufferedReader.close();
			}
			if (out != null) {
				out.close();
			}
		}
	}

	/**
	 * 替换标签
	 * 
	 * @param line
	 *            模板行
	 * @param buildTable
	 *            创建实例
	 * @return 替换后行
	 */
	private String replaceTags(String line, BuildTable buildTable) {
		String str = line;
		for (String tag : tags) {
			int pos = str.indexOf(tag);
			if (pos >= 0) {
				str = getTagConvert(tag).convert(str, tag, buildTable);
			}
		}
		str += "\n";
		return str;
	}

	/**
	 * 获取标签转换器
	 * 
	 * @param tag
	 *            标签
	 * @return 标签转换器
	 */
	private BaseTagConvert getTagConvert(String tag) {
		if ("#dao-hasDate#".equals(tag) || "#entity-hasDate#".equals(tag)) {
			return new HasDateConvert();
		} else if ("#dao-query#".equals(tag)) {
			return new DaoQueryConvert();
		} else if ("#bo-property#".equals(tag) || "#vo-property#".equals(tag)) {
			return new EntityPropertyConvert();
		} else if ("#entity-function#".equals(tag)) {
			return new EntityFunctionConvert();
		} else if ("#vo-toString#".equals(tag) || "#bo-toString#".equals(tag)) {
			return new EntityToStringConvert();
		} else if ("#list-grid#".equals(tag)) {
			return new ListGridConvert();
		} else if ("#list-query#".equals(tag)) {
			return new ListQueryConvert();
		} else if ("#form-input#".equals(tag)) {
			return new FormInputConvert();
		} else {
			return new DefaultConvert();
		}
	}

	public static void main(String[] args) {
		new CodeBuilder().build(true, "auth", "au_role");
	}

}
